package com.lineage.server.model.npc.action;

import com.lineage.server.datatables.ExpTable;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.L1Object;
import com.lineage.server.model.npc.L1NpcHtml;
import com.lineage.server.utils.RangeInt;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.w3c.dom.Element;

public abstract class L1NpcXmlAction implements L1NpcAction {
  public String _name;
  
  public String _npcids;
  
  private final int[] _npcIds;
  
  private final RangeInt _level;
  
  private final int _questId;
  
  private final int _questStep;
  
  private final int[] _classes;
  
  private static final Map<Character, Integer> _charTypes;
  
  static {
    (_charTypes = new HashMap<>()).put(Character.valueOf('P'), Integer.valueOf(0));
    _charTypes.put(Character.valueOf('K'), Integer.valueOf(1));
    _charTypes.put(Character.valueOf('E'), Integer.valueOf(2));
    _charTypes.put(Character.valueOf('W'), Integer.valueOf(3));
    _charTypes.put(Character.valueOf('D'), Integer.valueOf(4));
    _charTypes.put(Character.valueOf('R'), Integer.valueOf(5));
    _charTypes.put(Character.valueOf('I'), Integer.valueOf(6));
  }
  
  public L1NpcXmlAction(Element element) {
    this._npcids = null;
    this._name = element.getAttribute("Name");
    this._name = this._name.equals("") ? null : this._name;
    this._npcids = element.getAttribute("NpcId");
    this._npcIds = parseNpcIds(this._npcids);
    this._level = parseLevel(element);
    this._questId = L1NpcXmlParser.parseQuestId(element.getAttribute("QuestId"));
    this._questStep = L1NpcXmlParser.parseQuestStep(element.getAttribute("QuestStep"));
    this._classes = parseClasses(element);
  }
  
  private int[] parseClasses(Element element) {
    String classes = element.getAttribute("Class").toUpperCase();
    int[] result = new int[classes.length()];
    int idx = 0;
    char[] charArray;
    int length = (charArray = classes.toCharArray()).length;
    int i = 0;
    while (i < length) {
      Character cha = Character.valueOf(charArray[i]);
      result[idx++] = ((Integer)_charTypes.get(cha)).intValue();
      i++;
    } 
    Arrays.sort(result);
    return result;
  }
  
  private RangeInt parseLevel(Element element) {
    int level = L1NpcXmlParser.getIntAttribute(element, "Level", 0);
    int min = L1NpcXmlParser.getIntAttribute(element, "LevelMin", 1);
    int max = L1NpcXmlParser.getIntAttribute(element, "LevelMax", ExpTable.MAX_LEVEL);
    return (level == 0) ? new RangeInt(min, max) : new RangeInt(level, level);
  }
  
  private int[] parseNpcIds(String npcIds) {
    StringTokenizer tok = new StringTokenizer(npcIds.replace(" ", ""), ",");
    int[] result = new int[tok.countTokens()];
    int i = 0;
    while (i < result.length) {
      result[i] = Integer.parseInt(tok.nextToken());
      i++;
    } 
    Arrays.sort(result);
    return result;
  }
  
  private boolean acceptsNpcId(L1Object obj) {
    if (this._npcIds.length > 0) {
      if (!(obj instanceof L1NpcInstance))
        return false; 
      int npcId = ((L1NpcInstance)obj).getNpcTemplate().get_npcId();
      if (Arrays.binarySearch(this._npcIds, npcId) < 0)
        return false; 
    } 
    return true;
  }
  
  private boolean acceptsLevel(int level) {
    return this._level.includes(level);
  }
  
  private boolean acceptsCharType(int type) {
    return !(this._classes.length > 0 && Arrays.binarySearch(this._classes, type) < 0);
  }
  
  private boolean acceptsActionName(String name) {
    return !(this._name != null && !name.equals(this._name));
  }
  
  private boolean acceptsQuest(L1PcInstance pc) {
    if (this._questId == -1)
      return true; 
    if (this._questStep == -1)
      return (pc.getQuest().get_step(this._questId) > 0); 
    return (pc.getQuest().get_step(this._questId) == this._questStep);
  }
  
  public boolean acceptsRequest(String actionName, L1PcInstance pc, L1Object obj) {
    return (acceptsNpcId(obj) && acceptsLevel(pc.getLevel()) && acceptsQuest(pc) && 
      acceptsCharType(pc.getType()) && acceptsActionName(actionName));
  }
  
  public abstract L1NpcHtml execute(String paramString, L1PcInstance paramL1PcInstance, L1Object paramL1Object, byte[] paramArrayOfbyte);
  
  public abstract void execute(String paramString1, String paramString2);
  
  public L1NpcHtml executeWithAmount(String actionName, L1PcInstance pc, L1Object obj, long amount) {
    return null;
  }
}
